#include "StdAfx.h"

#include "NvApi.h"
#include "Enums.h"
#include "Physical Gpu.h"

using namespace StillDesign::NvApi;

NvApi::NvApi()
{
	_displays = gcnew ElementCollection<Display^>();
	_gpus = gcnew List<PhysicalGpu^>();
	
	int r = NvAPI_Initialize();
	
	switch( r )
	{
		case NVAPI_ERROR:
			throw gcnew NvApiException( "An error occurred during the initialization process (generic error)" );
		break;
		case NVAPI_LIBRARY_NOT_FOUND:
			throw gcnew DllNotFoundException( "Failed to load the NVAPI support library" );
		break;
		case NVAPI_OK:
			
		break;
		default:
			throw gcnew NvApiException( "Internal error" );
	}
	
	EnumDisplays();
	EnumPhysicalGpus();
}

void NvApi::EnumPhysicalGpus()
{
	NvPhysicalGpuHandle physicalGpuHandles[ NVAPI_MAX_PHYSICAL_GPUS ] = {0};
	NvU32 gpuCount = 0;
	
	int result = NvAPI_EnumPhysicalGPUs( physicalGpuHandles, &gpuCount );
	
	if( result == NVAPI_OK )
	{
		for( NvU32 x = 0; x < gpuCount; x++ )
		{
			NvPhysicalGpuHandle handle = physicalGpuHandles[ x ]; 
			
			_gpus->Add( gcnew PhysicalGpu( handle ) );
		}
	}else{
		throw gcnew NvApiException( "Unable to enumerate gpu devices. Error: {0}", (Status)result );
	}
}
void NvApi::EnumDisplays()
{
	NvAPI_Status nvapiStatus;
	NvDisplayHandle hDisplay_a[NVAPI_MAX_PHYSICAL_GPUS * 2] = {0};
	int nvDisplayCount = 0;
	
	// Enumerate all display handles
	for( int i = 0, nvapiStatus = NVAPI_OK; nvapiStatus == NVAPI_OK; i++ )
	{
		nvapiStatus = NvAPI_EnumNvidiaDisplayHandle( i, &hDisplay_a[ i ] );
		
		if( nvapiStatus == NVAPI_OK )
			nvDisplayCount++;
	}
	
	for( int i = 0; i < nvDisplayCount; i++ )
	{
		Display^ display = gcnew Display( hDisplay_a[ i ] );
		
		_displays->Add( display );
	}
	
	//
	
	_defaultDisplay = gcnew Display( NVAPI_DEFAULT_HANDLE );
}

DisplayDriverVersion NvApi::GetDisplayDriverVersion( Display^ display )
{
	if( display == nullptr )
		throw gcnew ArgumentNullException( "display" );
	
	NV_DISPLAY_DRIVER_VERSION version = {0};
	version.version = NV_DISPLAY_DRIVER_VERSION_VER;
	int error = NvAPI_GetDisplayDriverVersion( display->UnmanagedPointer, &version );
	
	if( error == NVAPI_OK )
		return (DisplayDriverVersion)version;
	else
		throw gcnew NvApiException( "An error occured whilst getting display driver version information. Error message: {0}", (Status)error );
}

ChipSetInfo NvApi::GetChipSetInfo()
{
	NV_CHIPSET_INFO info;
	info.version = NV_DISPLAY_DRIVER_VERSION_VER;
	
	int result = NvAPI_SYS_GetChipSetInfo( &info );
	
	ThrowOnError( result );
	
	return ChipSetInfo::ToManaged( info );
}

//

Display^ NvApi::DefaultDisplay::get()
{
	return _defaultDisplay;
}
ReadOnlyList<Display^>^ NvApi::Displays::get()
{
	return _displays->ReadOnlyCollection;
}
List<PhysicalGpu^>^ NvApi::Gpus::get()
{
	return _gpus;
}

int NvApi::MaximumPhysicalGpus::get()
{
	return NVAPI_MAX_PHYSICAL_GPUS;
}